﻿using System;
using Internal.KuiHuaBaoDian.Services.Battle.StateMachine;
using KuiHuaBaoDian.Services.Battle.Entity;
using KuiHuaBaoDian.Services.Battle.StateMachine;

namespace KuiHuaBaoDian.Services.Battle.StateMachine {

    /// <summary>
    /// 由<see cref="UnityEngine.Animator"/>进行显示播放的状态机
    /// </summary>
    public interface IBattleEntityStateMachine_Animator : IBattleEntityStateMachine {
    }

    [Implement(typeof(IBattleEntityStateMachine_Animator))]
    internal sealed class KHBD_BattleEntityStateMachine_Animator : KHBD_Object, IBattleEntityStateMachine_Animator, IBattleEntityStateMachineInternal_Animator {

        private static readonly int Idle = UnityEngine.Animator.StringToHash(nameof(Idle));
        private static readonly int IsMoving = UnityEngine.Animator.StringToHash(nameof(IsMoving));
        private static readonly int Die = UnityEngine.Animator.StringToHash(nameof(Die));
        private static readonly int Move = UnityEngine.Animator.StringToHash(nameof(Move));
        private static readonly int Attack = UnityEngine.Animator.StringToHash(nameof(Attack));

        private IBattleEntityAssetVehicle<UnityEngine.Animator> m_StateVehicle;
        private UnityEngine.Animator m_Animator;
        private IBattleEntityStateSpeedGetter m_SpeedGetter;

        public BattleEntityState State { get; set; }
        private BattleEntityState m_LastState;

        public bool IsInitialized => m_Animator != null;

        private bool m_ForceRefreshState;
        public bool IsStateChanged => State != m_LastState;

        private float m_PlaySpeed;
        private float m_OwnerSpeed;

        void IBattleEntityStateMachineInternal_Animator.Initialize(IBattleEntityAssetVehicle<UnityEngine.Animator> stateVehicle, IBattleEntityStateSpeedGetter speedGetter) {
            UnityEngine.Assertions.Assert.IsNotNull(stateVehicle);
            UnityEngine.Assertions.Assert.IsNotNull(speedGetter);

            m_StateVehicle = stateVehicle;
            m_SpeedGetter = speedGetter;
            m_StateVehicle.Loaded += OnStateVehicleLoaded;
            OnStateVehicleLoaded();
        }

        protected override void Dispose() {
            m_Animator = null;
            m_SpeedGetter = null;
            m_StateVehicle.Loaded -= OnStateVehicleLoaded;
            m_StateVehicle = null;
        }

        private void OnStateVehicleLoaded() {
            if (m_StateVehicle.Content == null) {
                return;
            }

            m_Animator = m_StateVehicle.Content;
            m_ForceRefreshState = true;
            Play(m_PlaySpeed);
        }

        public void Play(float speed) {
            m_PlaySpeed = speed;

            if (!IsInitialized) {
                return;
            }
            if (State == BattleEntityState.Unknown) {
                return;
            }

            if (IsStateChanged || m_ForceRefreshState) {
                m_ForceRefreshState = false;
                switch (State) {
                    case BattleEntityState.Move:
                        m_Animator.SetBool(IsMoving, true);
                        m_Animator.SetTrigger(Move);
                        break;
                    case BattleEntityState.Attack:
                        m_Animator.SetBool(IsMoving, false);
                        m_Animator.SetTrigger(Attack);
                        break;
                    case BattleEntityState.Die:
                        m_Animator.SetBool(IsMoving, false);
                        m_Animator.SetTrigger(Die);
                        break;
                    default:
                        m_Animator.SetBool(IsMoving, false);
                        break;
                }
                m_LastState = State;
            }

            float stateSpeed;
            var stateInfo = m_Animator.IsInTransition(0) ? m_Animator.GetNextAnimatorStateInfo(0) : m_Animator.GetCurrentAnimatorStateInfo(0);
            if (stateInfo.shortNameHash == Attack || stateInfo.shortNameHash == Move) {
                var speedValue = stateInfo.shortNameHash == Attack ? m_SpeedGetter.GetValue(BattleEntityState.Attack) : m_SpeedGetter.GetValue(BattleEntityState.Move);
                speedValue *= 2f; // 归一标准为0.5f
                stateSpeed = float.IsInfinity(stateInfo.length) ? speedValue : stateInfo.length * speedValue; // 归一， 以1秒1轮为标准攻速，动画时长(s) / 1(s) * 属性速度
            } else {
                stateSpeed = m_SpeedGetter.GetValue(State);
            }

            var playSpeed = stateSpeed * speed;
            if (playSpeed < 0f) {
                playSpeed = 0f;
            }
            m_Animator.speed = playSpeed;
        }
    }
}

namespace Internal.KuiHuaBaoDian.Services.Battle.StateMachine {

    public interface IBattleEntityStateMachineInternal_Animator : IBattleEntityStateMachine, IDisposable {

        void Initialize(IBattleEntityAssetVehicle<UnityEngine.Animator> stateVehicle, IBattleEntityStateSpeedGetter speedGetter);
    }
}